package com.cxyd.modules.wcs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.cxyd.common.constant.Constants;
import com.cxyd.common.constant.RcsConstants;
import com.cxyd.common.constant.WcsConstants;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.common.utils.ConvertUtils;
import com.cxyd.common.utils.StringUtils;
import com.cxyd.modules.api.dto.RcsResultHK;
import com.cxyd.modules.log.service.SysLogWorkService;
import com.cxyd.modules.wcs.dao.AgvTrkHkDao;
import com.cxyd.modules.wcs.dto.AgvTrkHkDTO;
import com.cxyd.modules.wcs.dto.AgvTrkHkPostDTO;
import com.cxyd.modules.wcs.dto.ApplyPassDTO;
import com.cxyd.modules.wcs.dto.PositionPathDTO;
import com.cxyd.modules.wcs.entity.*;
import com.cxyd.modules.wcs.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.util.*;

@Service
@Slf4j
public class AgvTrkHkServiceImpl extends CrudServiceImpl<AgvTrkHkDao, AgvTrkHkEntity, AgvTrkHkDTO> implements AgvTrkHkService {
    @Resource
    private TrkService trkService;
    @Resource
    private RouteSetService routeSetService;
    @Resource
    private PlcItemService itemService;
    @Resource
    private SysLogWorkService logWorkService;
    @Resource
    private PcItemService pcService;

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public AgvTrkHkServiceImpl() {
    }

    @Override
    public QueryWrapper<AgvTrkHkEntity> getWrapper(Map<String, Object> params) {
        String trkId = (String) params.get("trkId");
        String ctnrCode = (String) params.get("ctnrCode");
        String taskCode = (String) params.get("taskCode");
        QueryWrapper<AgvTrkHkEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(trkId), "trk_id", trkId);
        wrapper.eq(StringUtils.isNotBlank(ctnrCode), "ctnr_code", ctnrCode);
        wrapper.eq(StringUtils.isNotBlank(taskCode), "task_code", taskCode);
        wrapper.orderByDesc("create_date");
        return wrapper;
    }

    @Override
    public List<AgvTrkHkEntity> selectAll() {
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        return baseDao.selectList(qw.lambda());
    }

    @Override
    public AgvTrkHkPostDTO getPostHkTrk() {
//      1.获取需下发的任务(入库任务需要一个一个下发)
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getStatus, 0)
                .orderBy(true, true, AgvTrkHkEntity::getCreateDate)
                .last("limit 1");
        AgvTrkHkEntity agvTrkHK = baseDao.selectOne(qw);
        if (agvTrkHK == null) {
            return null;
        }
        AgvTrkHkPostDTO postInfo = ConvertUtils.sourceToTarget(agvTrkHK, AgvTrkHkPostDTO.class);
//      规划搬送路径(不再通过配置,直接从起始与结束位置获取)
        List<String> paths = Arrays.asList(agvTrkHK.getPositionCode().split("#"));
        List<PositionPathDTO> positionCodePath = new ArrayList<>();
        paths.forEach(item -> {
            PositionPathDTO path = new PositionPathDTO();
            path.setType("00");
            path.setPositionCode(item);
            positionCodePath.add(path);
        });
        postInfo.setPositionCodePath(positionCodePath);
        return postInfo;
    }

    @Override
    public ApplyPassDTO getContinueHkTrk() {
        //1.获取请求输送线状态的任务
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getStatus, RcsConstants.TASK_STATUS_APPLY)
                .orderBy(true, true, AgvTrkHkEntity::getUpdateDate)
                .last("limit 1");
        AgvTrkHkEntity agvTrkHK = baseDao.selectOne(qw);
        if (agvTrkHK == null) {
            return null;
        }
        //2.判断对应机械臂位置是否可取放
        boolean flag = itemService.signalJudge(agvTrkHK.getCtnrCode(), agvTrkHK.getAgvCode(), agvTrkHK.getCtnrTyp());
        if (!flag) {
            agvTrkHK.setData("线体暂不可取放!请等待...");
            agvTrkHK.setUpdateDate(new Date());
            baseDao.updateById(agvTrkHK);
            return null;
        }
        //3.生成任务继续信号
        ApplyPassDTO passDTO = new ApplyPassDTO();
        passDTO.setReqCode(String.valueOf(System.currentTimeMillis()));
        passDTO.setTaskCode(agvTrkHK.getTaskCode());
        passDTO.setReqTime(dateFormat.format(new Date()));
        return passDTO;
    }

    @Override
    public void hkTrkScan(TrkEntity wcsTrk) {
//        0.解析任务
        if (wcsTrk == null) {
            return;
        }
        String workName = "[流程-1]任务扫描-HK";
        String workProc = "AgvTrkHkServiceImpl.hkTrkScan";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg;
//        1.通过trkId尝试获取搬送任务是否存在
        AgvTrkHkEntity agvTrkHkEntity = getAgvTrkByTrkId(wcsTrk.getTrkId());
        if (agvTrkHkEntity != null) {
            //记录日志并返回
            pCode = "hkTrkScan_001";
            pMsg = "任务扫描异常!wcs任务[" + wcsTrk.getTrkId() + "]已存在!";
            wcsTrk.setTrkSt(WcsConstants.TRK_STATUS_ERROR);
            wcsTrk.setComments(pMsg);
            wcsTrk.setUpdateDate(new Date());
            trkService.updateById(wcsTrk);
            logWorkService.workLogging(workName, wcsTrk.getContNo(), pCode, pMsg, "", workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
        Long trkId = wcsTrk.getTrkId();
//        搬送路径与模板匹配
        RouteSetEntity routeSetByPath = routeSetService.getRouteSetByType(wcsTrk.getTrkType());
        String contNo = wcsTrk.getContNo();
        String contType = wcsTrk.getContType();
//        起始站点与目标站点均为实际站点,无需转换
        String positionCode = wcsTrk.getFrmPos() + "#" + wcsTrk.getToPos();
//        数据写入[AGV_TRK_HK]表(taskCode使用有含义的编码规则:托盘条码+年月日+6位trkId)
        String taskCode = String.valueOf(System.currentTimeMillis());
        String taskTyp = routeSetByPath.getTaskTyp();
//        防止reqCode重复，使用料箱码+时间戳
        String reqCode = contNo + System.currentTimeMillis();
//        任务优先级
        int trkPrty = wcsTrk.getTrkPrty();
        String taskMode = "0";
//        2.写入agv_trk_yf数据
        AgvTrkHkEntity agvTrkHkNew = new AgvTrkHkEntity();
        agvTrkHkNew.setTrkId(trkId);
//        wbCode用于记录工作台位置
        agvTrkHkNew.setPriority(WcsConstants.TRK_PRTY_DEF);
        agvTrkHkNew.setReqCode(reqCode);
        agvTrkHkNew.setTaskCode(taskCode);
        agvTrkHkNew.setTaskTyp(taskTyp);
        agvTrkHkNew.setPositionCode(positionCode);

        //如果是有两条任务一组的情况，那么优先级低的任务需要转为等待状态 1--低优先级  2--高优先级
        if (wcsTrk.getTrkPrty() == 1) {
            agvTrkHkNew.setStatus(6);
        } else {
            agvTrkHkNew.setStatus(0);
        }

//        CTU装载的容器编号
        agvTrkHkNew.setCtnrCode(contNo);
//        将任务类型写入AGV_TYP中
        agvTrkHkNew.setCtnrTyp(contType);
        agvTrkHkNew.setTaskMode(taskMode);
        agvTrkHkNew.setPriority(String.valueOf(trkPrty));
        agvTrkHkNew.setCreator(WcsConstants.WCS_USER_ID);
        baseDao.insert(agvTrkHkNew);
//        3.更新wcs_trk数据
        pMsg = "容器[" + contNo + "]生成[HK-AGV]搬送任务！关联ID[" + agvTrkHkNew.getId() + "]";
        wcsTrk.setTrkSt(WcsConstants.TRK_STATUS_RUNNING);
        wcsTrk.setComments(pMsg);
        wcsTrk.setUpdateDate(new Date());
        trkService.updateById(wcsTrk);
        logWorkService.workLogging(workName, wcsTrk.getContNo(), pCode, pMsg, "", workProc, WcsConstants.WCS_USER_NAME, 0);
    }

    @Override
    public AgvTrkHkEntity getAgvTrkByTrkId(long id) {
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getTrkId, id)
                .last("limit 1");
        return baseDao.selectOne(qw);
    }

    @Override
    public AgvTrkHkEntity getAgvTrkByContNo(String contNo) {
        if (StringUtils.isEmpty(contNo)) {
            return null;
        }
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getCtnrCode, contNo)
                .last("limit 1");
        return baseDao.selectOne(qw);
    }

    @Override
    public AgvTrkHkEntity getAgvTrkByTaskCode(String taskCode) {
        if (StringUtils.isEmpty(taskCode)) {
            return null;
        }
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getTaskCode, taskCode)
                .last("limit 1");
        return baseDao.selectOne(qw);
    }

    @Override
    public void agvTrkHandle(AgvTrkHkPostDTO dto, RcsResultHK response) {
//        1.判断任务是否下发成功
        String msg = response.getMessage();
//        2.成功下发更新任务状态为执行中,失败则记录失败原因(reqCode可能为空)
//        3.定义状态
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "搬送任务成功下发[HK-AGV]!任务编号[" + dto.getTaskCode() + "]";
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getTaskCode, dto.getTaskCode());
        AgvTrkHkEntity agvTrk = baseDao.selectOne(qw);
        int status;
        if (Constants.SUCCESS.equals(response.getCode())) {
            status = RcsConstants.TASK_STATUS_POST;

            //需要通知 plc任务状态
            PcItemEntity pcEntity = pcService.getPcItemByCode(agvTrk.getCtnrTyp(), "PC_REQ_STATUS");
            pcEntity.setItemValue(String.valueOf(RcsConstants.TASK_STATUS_POST));
            pcEntity.setStatus(1);
            pcService.updateById(pcEntity);
//            成功下发更新[wcs_trk]任务状态
        } else {
            status = RcsConstants.TASK_STATUS_ERROR;
            pCode = "agvTrkHandle_001";
            pMsg = "搬送任务下发失败!rcs反馈异常:" + msg;

            //需要通知 plc任务状态
            PcItemEntity pcEntity = pcService.getPcItemByCode(agvTrk.getCtnrTyp(), "PC_REQ_STATUS");
            pcEntity.setItemValue(String.valueOf(RcsConstants.TASK_STATUS_ERROR));
            pcEntity.setStatus(1);
            pcService.updateById(pcEntity);
        }
//        开始时间-start
        Instant start = Instant.now();
//        4.条件更新语句
        UpdateWrapper<AgvTrkHkEntity> uw = new UpdateWrapper<>();
        uw.lambda().set(AgvTrkHkEntity::getStatus, status)
                .set(AgvTrkHkEntity::getData, msg)
                .set(AgvTrkHkEntity::getReqTime, dateFormat.format(new Date()))
                .set(AgvTrkHkEntity::getUpdater, WcsConstants.WCS_USER_ID)
                .set(AgvTrkHkEntity::getUpdateDate, new Date())
                .eq(AgvTrkHkEntity::getReqCode, dto.getReqCode());
        baseDao.update(null, uw);
//        结束时间-end
        Instant end = Instant.now();
//        5.日志记录
        String workName = "[流程-3]任务下发-HK";
        String workProc = "AgvTrkHkServiceImpl.agvTrkHandle";
//        计算耗时
        Duration times = Duration.between(start, end);
        logWorkService.workLogging(workName, dto.getTaskCode(), pCode, pMsg, "", workProc, WcsConstants.WCS_USER_NAME, times.toMillis());
    }

    @Override
    public void agvPassHandle(ApplyPassDTO dto, RcsResultHK response) {
//        1.判断任务是否下发成功
//        2.成功下发更新任务状态为执行中,失败则记录失败原因
        if (StringUtils.isEmpty(response.getReqCode())) {
            return;
        }
        String msg = response.getMessage();
//        通过ReqCode获取取放申请的任务
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getTaskCode, dto.getTaskCode());
        AgvTrkHkEntity agvTrk = baseDao.selectOne(qw);
        String pCode = "0";
        String pMsg = "[step-3]料箱[" + agvTrk.getCtnrCode() + "]取放凭证下发AGV!申请类型[" + agvTrk.getAgvTyp() + "]";
        int status;
        if (Constants.SUCCESS.equals(response.getCode())) {
            status = RcsConstants.TASK_STATUS_GOING;

            //需要通知 plc任务状态
            PcItemEntity pcEntity = pcService.getPcItemByCode(agvTrk.getCtnrTyp(), "PC_REQ_STATUS");
            pcEntity.setItemValue(String.valueOf(RcsConstants.TASK_STATUS_GOING));
            pcEntity.setStatus(1);

            pcService.updateById(pcEntity);

//            成功下发更新[wcs_trk]任务状态
        } else {
            status = RcsConstants.TASK_STATUS_ERROR;
            pCode = "agvPassHandle_error_001";
            pMsg = "料箱[" + agvTrk.getCtnrCode() + "]取放凭证下发失败!申请类型[" + agvTrk.getAgvTyp() + "]rcs反馈异常:" + msg;

            PcItemEntity pcEntity = pcService.getPcItemByCode(agvTrk.getCtnrTyp(), "PC_REQ_STATUS");
            pcEntity.setItemValue(String.valueOf(RcsConstants.TASK_STATUS_ERROR));
            pcEntity.setStatus(1);
            pcService.updateById(pcEntity);
        }
//        更新agv_trk状态
        agvTrk.setStatus(status);
        agvTrk.setData(pMsg);
        agvTrk.setUpdateDate(new Date());
        baseDao.updateById(agvTrk);
        String workName = "通知AGV可入";
        String workProc = "AgvTrkService.agvPassHandle";
        logWorkService.workLogging(workName, agvTrk.getCtnrCode(), pCode, pMsg, "", workProc, "WCS系统", 0);
    }

    @Override
    public void updateAgvTrkByContNo(String contNo) {
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getCtnrCode, contNo)
//                .eq(AgvTrkHkEntity::getStatus, RcsConstants.TASK_STATUS_DONE)
                .last("limit 1");
        AgvTrkHkEntity AgvTrkHkEntity = baseDao.selectOne(qw);
        if (AgvTrkHkEntity == null) {
            return;
        }
//        1.转移历史表
        baseDao.backupAgvTrk(contNo);
        baseDao.deleteById(AgvTrkHkEntity);
    }

    @Override
    public void updateAgvTrkByTaskCode(String taskCode) {
//        1.转移历史表
        baseDao.backupAgvTrkByTaskCode(taskCode);
//        2.删除表数据
        baseDao.deleteAgvTrkByTaskCode(taskCode);
    }
}
